home *** CD-ROM | disk | FTP | other *** search
-
-
- CCMD
-
- TOPS-20 COMND JSYS EMULATION PACKAGE IN C
-
- Programmer's Guide
-
-
-
- INTRODUCTION:
-
- CCMD is a general parsing mechanism for developing User Interfaces to
- programs. It is based on the functionality of TOPS-20's COMND Jsys.
- CCMD allows a program to parse for various field types (file names,
- user names, dates and times, keywords, numbers, arbitrary text,
- tokens, etc.). It is meant to supply a homogeneous user interface
- across a variety of machines and operating systems for C programs.
- The library defines various default actions (user settable), and
- allows field completion, help, file indirection, comments, etc on a
- per field basis. Future plans include command line editing and ports
- to other operating systems (such as VMS). See the CCMD man page for
- more details on the user's view of CCMD. If you are installing CCMD,
- see the INSTALL file.
-
-
- 1) MACHINES/OPERATING SYSTEMS:
-
- CCMD currently runs under UNIX 4.2/4.3 BSD, Ultrix 1.2/2.0, System V,
- SunOS, Pyramid, DYNIX (Sequent-Balance 21000), Celerity, and MS-DOS
- 3.1.
-
-
- 2) INCLUDE FILES:
-
- The file "ccmd.h" should be included in your C source if you wish to
- use the ccmd package. Sometimes this will be found in the "local"
- subdirectory of the include directory. This file contains definitions
- for functions, flags, error codes, and structure declarations.
-
- This file will include some other CCMD files: "cmfnc.h", "ccmdmd.h",
- "datime.h", and "cmkeyval.h".
-
- Function specific symbols and declarations are in "cmfnc.h". Machine
- dependent macros and declarations are in "ccmdmd.h". Day and time
- parse related declarations are in "datime.h". "cmkeyval.h" declares
- the types "keyval" and pointer to function (cmprocptr).
-
-
- 3) DATA STRUCTURES:
-
- Below are a few of the data structures that you need to know about in
- order to use ccmd.
-
- a) fdb
-
- The fdb structures hold information required to parse specific fields
- of a command line.
-
- typedef struct FDB {
- int _cmfnc; /* Function code for this field */
- int _cmffl; /* Function specific parse flags */
- struct FDB * _cmlst; /* Link to alternate FDB */
- pdat _cmdat; /* Function specific parsing data */
- char * _cmhlp; /* pointer to help string */
- char * _cmdef; /* pointer to default string */
- brktab * _cmbrk; /* pointer to special break table */
- } fdb;
-
- i) _cmfnc:
-
- The function code specifies what type of parse is to be done.
- The function code (_cmfnc) can be one of the following:
-
- _CMCFM parse for a confirm (carriage return)
- _CMKEY parse for a keyword (from a table of keywords)
- _CMNUM parse a number (of the specified radix)
- _CMQST parse a quoted string
- _CMNOI parse a noise (guide) string
- _CMTXT parse text up to end of line
- _CMFLD parse a single field
- _CMSWI parse a switch (switch character followed by keyword)
- _CMTOK parse a token
- _CMTAD parse a time and/or date specification
- _CMFIL parse a file name
- _CMUSR parse a user name
- _CMGRP parse a group name
- _CMPARA parse a "paragraph" of text
- _CMCHAR parse a single character
-
- Each of these parse types will be discussed in detail later.
-
- ii) _cmffl:
-
- _cmffl is the function specific parse flags for the above types of
- parses. (See the discussion on the individual parse types for more
- detail on this.)
-
- In addition to the function specific flags, there is one flag that is
- common to all parse types. This is CM_SDH which is used to suppress
- the default help message associated with the parse type. This is
- commonly used when you wish to supply your own help message (see
- _cmhlp below).
-
- iii) _cmlst:
-
- _cmlst is a pointer to an alternate fdb. A chain of fdbs may be
- passed to the parser which will try to use one of the fdb's in a
- successful parse. The fdbs in the chain are considered in the order
- that they are linked in, and thus it is up to the programmer to chain
- them in the proper order in cases when an input may satisfy more than
- one fdb.
-
- The last fdb's _cmlst field should be the NULL pointer.
-
- The function fdbchn() may be used to set up the chain. Further
- details appear later in this guide.
-
- iv) _cmhlp:
-
- A help string may be provided in addition to or in place of the
- default help provided for a parse type. Note that in parses with
- chained fdbs, the help messages appear in the order that the fdbs are
- chained.
-
- To suppress the default help message associated with a parse type, the
- CM_SDH flag may be set in the fdb (see _cmffl above).
-
- v) _cmdat:
-
- The _cmdat field is used to supply parse type specific data to the
- parser. See the discussion on the various parse types for more
- details on this field.
-
- vi) _cmdef:
-
- The _cmdef field is used to supply a default string to the parser.
- If no other fdb in the chain has parsed the command line successfully
- up to the current fdb, and if this fdb has a default string, then the
- parse will succeed as if the default had been typed by the user.
- Note, that the user can type some other string satisfying this fdb, in
- which case the user's data takes precedence.
-
- vii) _cmbrk:
-
- This field contains a pointer to a special break table to be used
- during this parse. A break table specifies which characters are valid
- for this particular field. All other characters will cause the parser
- to break out of this parse. The structure of the break table (brktab)
- is discussed below.
-
-
- b) brktab
-
- A break table specifies the characters that will cause the parser to
- break out of the current parse.
-
- typedef struct BRKTAB {
- char _br1st[16]; /* Bit array for initial character breaks */
- char _brrest[16]; /* Bit array for subsequent breaks */
- } brktab;
-
- brktab is a pair of 128-bit arrays specifying the break
- characteristics of the ASCII characters. The _br1st array specifies
- characters which will break field input when they are typed as the
- first character of a field. The _brrest array specifies characters
- that break in other than the first position. Each array contains one
- bit per ASCII code, ordered according to the ASCII sequence. The
- leftmost (most significant) bit of the first byte corresponds to ASCII
- code 0, and the rightmost bit of that same byte corresponds to ASCII
- code 7. Leftmost bit of the second bit is for ASCII code 8, and so
- on. When a bit is on, the corresponding character will act as a break
- character, otherwise it will not.
-
- The default break tables for each parse type will be mentioned in the
- section describing the parse types.
-
- XXX Mention break table utils in ccmdut when they get written XXX
- XXX Mention brk, document it, etc. XXX
- XXX Also, give an example where br1st and brrest are diff't. XXX
-
- c) pval:
-
- Pval is a union in which ccmd returns parsed values. Each parse type
- will use one of the fields, whichever is appropriate. The structure
- of pval is as follows:
-
- typedef union PVAL {
- int _pvint; /* integer return value */
- float _pvflt; /* XXX floating point return value */
- char _pvchr; /* single character */
- char *_pvstr; /* string */
- char **_pvstrvec; /* XXX ??? XXX */
- keyval _pvkey; /* keyword and switch index */
- datime _pvtad; /* date and/or time */
- pvfil _pvfil; /* file(s) */
- struct passwd ** _pvusr; /* passwd entries for parsed users */
- struct group ** _pvgrp; /* group entries for parsed groups */
- char * _pvpara; /* "paragraph" of text */
- } pval;
-
- Here is a list of all the parse types and the field to look at for the
- parsed value:
-
- Parse type Field Comment
- ------------------------------------------------------------
- Confirm (CMCFM) <none> parse succeeds/fails
- Keyword (CMKEY) _pvkey value specified for keyword
- Number (integer)(CMNUM) _pvint
- Quoted string (CMQST) _pvstr quotes are stripped off XXX ?
- Noise string (CMNOI) <none> parse succeeds/fails
- Text string (CMTXT) _pvstr
- Field (CMFLD) _pvstr
- Switch (CMSWI) _pvkey value specified for switch
- Token (CMTOK) <none> parse succeeds/fails
- Date/time (CMTAD) _pvtad struct datime (see below)
- File name(s) (CMFIL) _pvfil array of char strings
- User name(s) (CMUSR) _pvusr array of struct passwd
- Group name(s) (CMGRP) _pvgrp array of struct group
- Paragraph (CMPARA) _pvpara char string
- Character (CMCHAR) _pvchr
-
-
- d) csb
-
- The csb structure holds information on the state of parsing a command
- line, as well as pointers to required buffers. CCMD uses the global
- csb called cmcsb (externed in ccmd.h).
-
- typedef struct CSB {
- int _cmflg; /* flags describing parse state */
- int _cmflg2; /* more flags */
- FILE * _cmij; /* file for command input */
- FILE * _cmoj; /* file for command output */
- FILE * _cmej; /* file for error output */
- char * _cmrty; /* pointer to prompt string */
- int * _cmbfp; /* pointer to beginning of user input */
- int * _cmptr; /* pointer to beg of next field to parse */
- int _cmcnt; /* # of chars in buffer past _cmptr */
- int _cminc; /* number of unparsed chars after _cmptr */
- int * _cmhst; /* history parse point */
- char * _cmabp; /* pointer to beginning of atom buffer */
- int _cmabc; /* size of atom buffer */
- char * _cmwbp; /* pointer to beginning of work buffer */
- int _cmwbc; /* size of work buffer */
- int (** _cmact)(); /* table of character action routines */
- int _cmbkc; /* break character that caused deferred */
- /* action or confirmation */
- int _cmcmx; /* maximum column position on terminal */
- int _cmcol; /* current column position on terminal */
- int _cmerr; /* most recent parse error */
- fdb * _cmifd; /* ptr to FDB giving an incomplete parse */
- int (* _cmrph)(); /* function to call when reparse is needed */
- int (* _cmerh)(); /* function to call on parse error */
- char * _cmntb; /* comment to eol string */
- char * _cmnts; /* delimited comment beginning */
- char * _cmnte; /* delimited comment end */
- int _cmmax; /* maximum number of help tokens to display */
- int (* _cmblh)(); /* function to call nonblocking and no data */
- int _cmwrp; /* column to wrap at */
- cmhist *_cmhist; /* command history structure */
- } csb;
-
- Most of these fields are only used internally by CCMD. The ones that
- are most likely to be used externally are _cmij, _cmoj, and _cmej --
- the input, output and error file descriptors. Changing these
- redirects input and output for parsing. Using them allows consistency
- when CCMD is using alternate input/output. _cmerr is another field of
- interest, since it tells why CCMD failed in the most recent parse.
- _cmwrp is used for paragraph parses to do automatic word wrap, and is
- optimally settable by the user. _cmact can be used to change the
- actions on various characters. XXX how? Why?
-
- XXX general history description, mention history length setting
-
- When debugging, there are a few other things you may want to look at
- to see what has been typed and what has been parsed.
- XXX describe what's in cmabp and cmwbp strings, maybe cmbfp
- Note, however, that these strings are not null-terminated -- you will
- want to check the length (_cmabc and _cmwbc, respectively) of the
- strings.
-
- At initialization time, you can set necessary fields in the csb using
- cmini(), as described below.
-
-
- e) datime
-
- datime is the structure returned by a day and/or time parse (CMTAD).
- Below is what this structure looks like:
-
- typedef struct DATIME {
- short _dtmon; /* 0 = January, 11 = December */
- short _dtday; /* 0 = first day of month */
- int _dtyr;
- short _dtdow; /* day of week: 0 = Sunday, 6 = Saturday */
- short _dthr; /* 0 to 23 */
- short _dtmin;
- short _dtsec;
- int _dttz; /* time zone, # of mins west of Greenwich */
- /* (this is the number of minutes to add */
- /* in order to get GMT) */
- int _dttzc; /* time zone code, one of TZ_XXX codes */
- /* defined below, or -1 */
- int _dtdst; /* additional minutes to shift due to */
- /* daylight savings time (generally -60 */
- /* when dst is in effect and 0 otherwise) */
- } datime;
-
- 00:00:00 is considered the beginning of a day. If only a date is parsed,
- the time returned will be 00:00:01 of the parsed date.
-
- Note that most of these fields correspond to fields of the UNIX tm
- structure. However, the datime structure's _dtday field starts at 0
- while the tm structure's tm_mday starts at 1.
-
- XXX describe TZ_XXX's
-
- f) keywrd
-
- The keywrd structure is used for _CMKEY and _CMSWI parses. It
- contains a keyword to be parsed and a value to identify which keyword
- was parsed. It also contains a flag field for various flags. After a
- successful parse, the parse value (_pvkey field) will be set to the
- keyword value of the matched keyword.
-
- typedef struct KEYWRD {
- char * _kwkwd; /* keyword string */
- short _kwflg; /* flags (see below) */
- keyval _kwval; /* arbitrary value, not used internally */
- /* except for abbreviations... see KEY_ABR */
- /* flag below */
- } keywrd;
-
- A set of keywrds is stored in an array, usually (though not
- necessarily) in alphabetical order. When a question mark is typed,
- they will be displayed in this order.
-
- The flags that a keyword can have are: KEY_NOR, KEY_IGN, KEY_INV, and
- KEY_ABR.
-
- KEY_NOR and KEY_IGN are two names for the same flag, which means
- ignore this keyword. (KEY_NOR is for TOPS20 compatibility (CM%NOR),
- and KEY_IGN is an easier name to remember.) This flag can be used to
- "turn off" certain keywords in a dynamic table without having to
- remove the entry. (Sort of like the grey-shaded options in a
- MacIntosh menu.) It can also be used to disallow certain
- abbreviations of other keywords -- so if you did not want the keyword
- "really-dangerous" to be shortened to "r" even if it was the only
- keyword starting with "r", you would add the keyword "r" with KEY_IGN
- turned on. Note that this flag does NOT imply KEY_INV (see below),
- but you will probably always want to have ignored keywords be
- invisible.
-
- KEY_INV makes a keyword invisible. That is, the keyword will not show
- up when a question mark is typed. This is most often used for
- synonyms, to avoid clutter. Thus, if you have an "exit" command, but
- many of your users are accustomed to typing "q" to exit, you could
- have "quit" as an invisible keyword, probably with the same keyval as
- "exit".
-
- KEY_ABR makes this keyword be an abbreviation of another one. Since a
- unique prefix of a keyword will match that keyword, this is used to
- make a non-unique prefix match a specific keyword. To specify which
- keyword the abbreviation is for, the offset of the that keyword in the
- current table (starting with zero) is placed in the _kwval field.
- (The value returned when the abbreviation is typed is the value for
- that keyword.)
-
- For example, if you have the keywords "delete" and
- "do-something-really-obscure-and-complicated", you could make "d" be
- an abbreviation for "delete". Then a user typing just "d" would get
- the "delete" keyword, and ESC would finish the word "delete". For
- this reason, the abbreviation should be a prefix of the other keyword,
- since otherwise CCMD cannot complete it.
-
- The kwval field can be used in various ways. During command parsing,
- you will probably want the key value to specify which function should
- be called for further parsing of the command. This can be done in
- various ways. One of the slickest ways is to make the actual address
- of the function be the value. However, this does not work on all
- computer systems. A similar method, which works anywhere but is a
- little harder to maintain, is to have an array of functions indexed by
- the key value. Then you would call the function like this:
-
- (void) (*func_array[parseval._pvkey]) ();
-
- g) keytab
-
- The keytab structure holds information about the keywrd array for a
- keyword parse.
-
- typedef struct KEYTAB {
- int _ktcnt; /* number of keywords in table */
- keywrd * _ktwds; /* array of keyword entries */
- } keytab;
-
- It can be set up as follows:
-
- keytab footab = { (sizeof(foowrds)/sizeof(keywrd)), foowrds };
-
- if foowrds is the name of a static keywrd array.
-
- h) filblk
-
- Used for file parses
- XXX
-
- typedef struct FILBLK {
- char **pathv; /* NULL terminated vector of dirs */
- char *exceptionspec; /* regexp of exceptions */
- char **def_extension; /* list of extensions to use */
- } filblk;
-
- The pathv field is used to give a path for filenames. By default, the
- path is just ".", the current directory. It should be a
- null-terrminated array of directory names (with no terminating slash).
- The exceptionspec is a regular expression describing filenames to
- ignore -- for example, "*.o" as an exception would make sense for an
- editor, which would probably only want text files. def_extension is a
- null-terminated array of extensions, for completion. This is useful
- if you want to parse for files that end with ".c", ".txt", or
- whatever.
-
- XXX what are exceptionspec and def_extension?
-
- XXX para_data, para_actions
- XXX More data structures?
-
- 4) PARSE TYPES:
-
- Each of the function types that can be in the _cmfnc field of an fdb
- corresponds to a different type of thing CCMD can parse.
-
- Keywords and switches, filenames, user names, and group names are all
- parsed rather similarly, since they can all be thought of as
- variations on a keyword parse. That is, a question mark will actually
- list all the keywords, filenames, user or group names that match the
- current input (unless there are too many, defined by the _cmmax field
- of the csb).
-
- a) _CMCFM
-
- This is used to parse a confirm, or carriage return. You can use the
- CCMD function confirm() to just parse a confirm, or chain a confirm in
- with other fdbs, making those other parse elements optional.
-
- A confirm should be done at the end of most commands. One exception
- is a command that ends with a text parse, since the confirm gets
- parsed as the terminator of the text.
-
- _CMCFM takes neither function specific flags or data.
-
- b) _CMKEY and _CMSWI
-
- These two functions, keyword and switch, will try to match a keyword
- to one of a list of keywords (see keywrd and keytab data structures
- above). A switch begins with a "switch character" (this is settable),
- usually a slash (/), and is more often optional. These are like UNIX
- options and VMS or TOPS20 switches.
-
- Keywords are often used at the beginning of a command parse, to pick
- out which of a list of commands will be executed.
-
- The fdb for a keyword or switch parse needs a keytab (described above)
- in the _cmdat field. Note that for a switch's keywrds, the switch
- character should not be in the keywrd strings. This makes it possible
- to use the same keytab for both keywords and switches.
-
- There are no function-specific flags in _cmffl for _CMKEY and _CMSWI.
-
- c) _CMNUM
-
- This is used to parse a number in any radix (up to 16 -- hexadecimal).
- The radix is specified as the _cmdat field of the fdb. There are
- three flags possible for a number parse. NUM_US parses for (XXX and
- returns?) an unsigned integer. XXX NUM_BNP (break on
- non-punctuation)?? NUM_PO (parse-only) tells CCMD to parse something
- that qualifies as a number in the specified radix without determining
- what number it is. In this case, you might want to look at the _cmabp
- field of the csb to find out what string was parsed.
-
- d) _CMQST
-
- This is used for parsing a quoted string. It expects to see a double
- quote as the first character of the field, and will include everything
- up to the next double quote in the string. A quoted string parse
- would be used when looking for a field that might contain spaces. It
- is similar to a text parse (see _CMTXT below) but ends before the end
- of line.
-
- XXX settable delimiters
-
- e) _CMNOI
-
- Noise words are a type of mid-parse comments used to give hints about
- what should be typed next, or what this command does. Since noise
- words are not required to be typed, you will almost never want to
- build a _CMNOI fdb, but will most likely just use the noise() routine
- (see below).
-
- Noise words are displayed on escape after the previous field has been
- successfully completed. They are shown in parentheses to emphasize
- that they need not be typed.
-
- The _cmdat field of a _CMNOI fdb should be the noise string (without
- parentheses).
-
- f) _CMTXT
-
- A text parse is used to parse about a line of any sort of text. It is
- terminated at end of line. For longer parses, see _CMPAR below.
-
- g) _CMFLD
-
- A field parse gets one "word" of the input string. The word is
- delimited by whichever characters are in the current break mask.
-
- There is one flag available for a field parse, FLD_EMPTY, which when
- set does not allow an empty field (otherwise, a cmfld parse can
- succeed without parsing any characters).
-
- h) _CMTOK
-
- A token can be either a one character punctuation or a sort of
- one-word keyword table. A token must exactly match the input.
-
- The token string is specified in the _cmdat field of the fdb.
-
- The flag TOK_WAK means white space after the token is not required --
- this allows help on "?" to work immediately after the entire token is
- entered.
-
- i) _CMTAD
-
- One of the most complicated parses CCMD can do is a time and day
- parse. It allows for a large number of different formats. This is in
- part seen by the numerous flags available.
-
- DTP_NTI: do not parse time
- DTP_N24: no 24-hour time format allowed
- DTP_NTM: no AM/PM specifier allowed
- DTP_NIS: seconds may not be specified
- DTP_AIS: seconds must be specified after colon
- DTP_NAC: colon cannot appear between hours and minutes
- DTP_AAC: colon must appear between hours and minutes
- DTP_AHM: first number in time cannot be both hours and minutes
- DTP_AMS: first number in time is both hours and minutes unless too
- many colons for this
- DTP_NTZ: no time zone allowed in input
- DTP_NDA: do not parse date
- DTP_NNM: month may not be numeric
- DTP_SNM: second of two date numbers is month (unless second number is
- greater than 12)
- DTP_ERR: do not swap month/day numbers if DTP_SNM setting implies range error
- DTP_NDW: do not allow day-of-week in input
- DTP_NSP: do not allow time to split date before year, as BSD's ctime
- call does (e.g. Saturday, 9 March 9:52am 1986)
-
- As an example, here are some of the formats accepted for Monday,
- July 25, 1988 at 6:30 pm.
-
- 7-25-88 18:30
- 25-7-1988 18:30
- July 25, 1988 6:30 PM
- Mon July 25 18:30:00 EDT 1988
- Monday, July 25, 1988 630 p
-
- j) _CMFIL
-
- Another of CCMD's more complicated parses is the filename parse. In
- addition to the options available via an optional filblk structure
- (described above) in the _cmdat field, there are many flags.
-
- Since wildcards (and, eventually, regular expressions) can be allowed
- in the filename, it is possible to parse more than one file name, so
- all matching filenames are returned in an array of strings, terminated
- by a NULL string pointer.
-
- FIL_OLD: existing file
- FIL_PO: file need not exist (parse-only)
- FIL_SDH: don't give standard help (list of filenames)
- FIL_DIR: a directory
- FIL_RD: a readable file
- FIL_WR: a writable file
- FIL_EXEC: an executable file
- FIL_HID: a hidden file (in MSDOS)
- FIL_SYS: a system file (in MSDOS)
- FIL_WLD: wild cards allowed
- FIL_REGEXP: regular expressions allowed (not yet implemented)
- FIL_NOPTH: only display filename in help, not whole directory path
- FIL_NOEXT: don't display extension in help
- FIL_TYPE: display the type of file in help
- FIL_NODIR: don't complete on directories (for parsing non-directory files)
- FIL_RW: a readable and writable file
-
- The union of the files matching the flags is used -- thus using the
- flags FIL_RD and FIL_WR will parse for a file which is either readable
- or writable or both.
-
- Setting no flags at all will parse for any (existing) file.
-
- k) _CMUSR and _CMGRP
-
- These can be used to parse for a user or group name on the local
- machine. The user must exist and be in the password file. The group
- must be in the group file. The name may contain wildcards (if
- USR_WILD or GRP_WILD is set), so an array containing password (or
- group) entries for all matching names is returned. Again, the end of
- the array is the first NULL entry.
-
- USR_WILD or GRP_WILD: allow wildcards in user/group names
- USR_NOUPD or GRP_NOUPD: defer update of user or group table, even if
- /etc/passwd or /etc/groups has been updated -- this is used
- when there are so many users/groups on the system that an
- update will cause a significant wait
- USR_UPDONLY or GRP_UPDONLY: forced update of user or group table
- (parse will fail) -- allows table to be updated with no
- parse done. When using this flag, you must trap errors
- yourself (using cmseter() as described below), or a "no such
- user/group" error will be displayed
-
- l) _CMPARA
-
- For extended amounts of text, you will want to use the paragraph
- parse. (A "paragraph" can really be more than one paragraph, but we
- will continue to use that phrase.) _CMPARA cannot be chained with
- other fdbs (since it wouldn't make sense anyway). It will continue
- parsing until an end-of-text (usually control-D) is typed. In
- addition, several utility functions can be invoked while the paragraph
- is being typed.
-
- Control-B is used to insert a file into the paragraph. It will prompt
- for a file name and insert the contents of the file.
-
- Control-E invokes the user's editor (either from their EDITOR
- environment variable or a default) on the current paragraph, by
- writing it out to a temporary file. Once the editor exits, CCMD reads
- the paragraph back in from the file.
-
- Control-F runs the paragraph through a filter. This is similar to the
- edit command, but is used with non-interactive programs. For example,
- if you had a program that took text and put it into two columns, you
- could use this as a filter after finishing your paragraph.
-
- Control-K can be used to redisplay the paragraph. This is useful for
- when some other program writes to the user's screen. Similarly,
- control-L redisplays the paragraph after first clearing the screen.
-
- Control-N is used to abort the parse, and is similar to the effect of
- control-U on a line.
-
- Control-P executes a command and inserts the output into the
- paragraph. This can be simulated in Unix by sending the output of a
- command to a file and then using ^B to insert the file.
-
- Space, tab, and newline invoke a special word wrapping routine. The
- column at which wrapping is done is specified in the _cmwrp field of
- the csb (see above). If the number is positive, it is taken as an
- absolute value. If negative, it is subtracted from the number of
- columns on the user's screen. A zero value turns wrapping off.
-
- You can add your own set of routines to be used during paragraph
- parsing using the para_actions structure described above. Also, you
- can continue a paragraph parse (or start one with some text already
- entered) by filling in the buf field of the para_data structure. If
- you do this kind of modification, the para_data structure goes in the
- _cmdat field of the fdb.
-
- The one flag available for _CMPARA is PARA_DEF, which controls the
- effect of the para_actions structure (within the para_dat in the
- _cmdat field). If PARA_DEF is set, the default actions are combined
- with the new actions. Otherwise, the defaults are overridden.
-
- m) _CMCHAR
-
- _CMCHAR simply parses one character. It is essentially the CCMD
- version of getc().
-
- XXX default break tables for each function
-
- 5) CCMD EXTERNAL FUNCTIONS AND MACROS:
-
- Along with the actual parse() routine (see below), CCMD provides
- various supplementary functions (some of which are actually macros).
-
- XXX Shall we use ANSI C prototyping format? Or man page prototyping
- XXX format? (Maybe our man pages should start using ANSI
- XXX prototyping!)
-
- a) cmini()
-
- cmini() initializes CCMD by running cmbufs() and cmseti() (see below).
- It provides the buffers for cmbufs, and returns the address of the
- atom buffer. For cmseti(), it supplies standard input, output and
- error.
-
- b) cmbufs(cmdbuf, cmdlen, atombuf, atomlen, workbuf, worklen)
- int *cmdbuf;
- char *atombuf, *workbuf;
- int cmdlen, atomlen, worklen;
-
- This is used to initialize various buffers in the csb. (The command
- buffer is an array of integers in order to hold flags about the
- characters in the command.) These buffers will generally have lengths
- of about 200.
-
- c) cmseti(input, output, error)
- FILE *input, *output, *error;
-
- This sets up the _cmij, _cmoj, and _cmer fields of the csb to direct
- or redirect input, output, and error. Then cmtset() is called (see
- below). This should be done at startup time, and whenever parsing is
- to be done to/from an alternate file. (Note that cmtake(), below,
- takes care of this.)
-
- d) cmtset()
-
- This determines whether the output file is a tty, and if so it reads
- termcap to find out about this particular tty. This is when changes
- to the terminal's attributes (notably echo, or cbreak mode) are done.
-
- e) cmseter() and cmsetrp()
-
- cmseter() and cmsetrp() are actually macros, but this should not
- affect your program. Neither of them takes any arguments -- they
- simply use setjmp() to set a location.
-
- cmseter() sets the location to return to on parsing errors, to try to
- parse something valid. So, if an invalid command is typed, CCMD will
- try to parse again.
-
- cmsetrp() sets where parsing will resume if the user deletes through a
- field that has already been parsed. Rather than trying to unravel
- just the lines of code and functions executed since that field was
- parsed, CCMD will go back to the beginning and parse the line over.
-
- Since cmseter() and cmsetrp() are implemented with setjmp() and
- longjmp(), they can be a source of memory leaks. Therefore, you
- should be very aware of storage that is dynamically allocated during a
- parse. Until the command is confirmed, your program may longjmp()
- back to the cmseter() or cmsetrp() location whenever the parse()
- function (see below) is in progress.
-
- A good way to keep track of dynamic storage in this situation is to
- use a static pointer which gets set to NULL when it is not pointing to
- anything. Then, if you enter the function and the pointer is
- non-NULL, you will know you have to free the storage.
-
- f) prompt(str)
- char *str;
-
- This sets up the string that will be used for prompting. It is
- generally done before the first parse of a command, inside a command
- parsing loop.
-
- prompt() also resets a few internal variables, and thus should be used
- even when handling arguments from the command line (see cmargs()
- below), though a NULL prompt string is recommended in that situation.
- In addition, if cmseti() has not been done it will be automatically
- called.
-
- g) fdbchn (fdb1, [ fdbn, ] ... NULL)
- fdb fdb1, fdbn;
-
- When chaining multiple fdbs together, or even when using a single fdb
- that previously was chained, the fdbchn() routine is used. It accepts
- a variable number of arguments, all fdb pointers, the last of which
- should be NULL. These fdbs are linked together (using their _cmlst
- fields) in the order given.
-
- Note that if an fdb is chained with other fdbs, and then later gets
- used on its own, you should make sure that its _cmlst field actually
- is NULL. To do this, you can simply call fdbchn() with this fdb and
- NULL.
-
- h) cmargs (argc, argv);
- int argc; char **argv;
-
- This routine allows command line parsing. It returns TRUE if there
- are arguments in the command line, and places them in a buffer as
- though they were coming in from CCMD's input stream. They may then be
- parsed as desired. On subsequent calls, and when there are no
- arguments present, cmargs() will return FALSE.
-
- i) noise(str)
- char *str;
-
- This is just shorthand for parsing _CMNOI. Note that it will affect
- CCMD's parsing buffers (see cmbufs, above).
-
- j) confirm()
-
- Similarly, shorthand for parsing _CMCFM.
-
- k) cmtake(fnc)
- int (*fnc) ();
-
- This routine processes the standard "take" command. It parses for a
- command file, as well as output and error files, and redirects CCMD's
- file descriptors accordingly (through cmseti(), as described above).
- Then it calls the given function to start parsing from the new input.
- It expects that on end of file the function will return.
-
- If a take command with no filename arguments is given while within a
- take file, end of file is simulated.
-
- Take files allow users to easily execute a set of "canned" commands.
- Command history is turned off while parsing from the alternate file,
- since it could be a lengthy set of commands.
-
- l) cmpasswd (prompt)
- char *prompt;
-
- This parses a password, prompting with the specified string, in an
- appropriate manner. Echo is turned off so no one can see the
- password, and command history is temporarily suspended so no one can
- look it up later. The parsed password string is returned.
-
- m) cmsystem(cmd)
- char *cmd;
-
- This works just like the regular system() call, except CCMD's control
- of the terminal is turned off while system() is running, using
- cmtset() (above) and cmtend() (below).
-
- n) cmdone() or cmtend()
-
- This function (with two names) is sort of the opposite of cmtset()
- above, and should be done when you are finished using CCMD, usually
- right before exiting or suspending the program. It puts all the
- terminal attributes back the way they were before the program started.
-
- If you catch SIGTSTP or SIGINT you should execute cmdone() in their
- handlers. If you do not catch these, CCMD will catch them for you and
- take care of things. Having done cmdone() yourself before suspending
- execution, you will want to do cmtset() (see above) as soon as the
- program starts up again, inside the SIGTSTP handler.
-
- o) cmcls()
-
- This function simply uses CCMD's knowledge of the terminal type to
- clear the screen.
-
- XXX diff between datime_to_time and MM's datimetogmt -- why?
- XXX datime_to_time, cmxprintf, cm_set_ind (cmmisc.c), cmhist(), ...
-
- 6) ERROR CODES:
-
- XXX error codes returned from cmseter()
-
- 7) PARSING:
-
- XXX expand. code sample
-
- Here's the part you really want -- finally using CCMD to parse a
- command from the user. Before parsing, you must either run cmini() or
- use the other CCMD routines, as described above, for initialization.
- fdbs for the desired parse should be set up. You will need a pval
- structure, say "pv", and a pointer to an empty fdb structure, call it
- "used".
-
- First, you tell CCMD where to go if the user types the wrong thing, by
- using cmseter() (see above). Since this sets the location to go after
- errors, you will probably want to do
-
- cmcsb._cmerr = CMxOK
-
- to clear whatever error occurred (or you might check the error).
-
- Next, you prompt() them for a command. Then you'll want to set the
- reparse location with cmsetrp(). Thus, if the user types an incorrect
- command, CCMD will reprompt them and try again. If they delete part
- of the command, it will reparse the command.
-
- At this point, you pick your fdb and parse().
-
- parse (fdbs, &pv, &used)
- fdb *fdbs; pval pv; fdb *used;
-
- "fdbs" is either the fdb you wish to use or the first of a chain of
- fdbs. After the parse, "used" will contain a pointer to the fdb that
- was used. This is for when you have a chain of fdbs, so you can find
- out just which fdb the parse succeeded on. Knowing which fdb was used
- will tell you how to interpret "pv".
-
- There you go. You've parsed. Don't forget to cmdone() when you're
- done, so the user gets their terminal back intact.
-
- 8) COPYRIGHT:
-
- CCMD is copyright (c) 1986, 1990 by The Trustees of Columbia University in
- the City of New York. Permission is granted to any individual or
- institution to use, copy, or redistribute this software so long as it
- is not sold for profit, provided this copyright notice is retained.
-